/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.tenancy.core.service;

import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.tenancy.api.entity.AppInstanceInfo;
import io.iec.edp.caf.tenancy.api.exception.NoMatchingAppInstanceFound;
import io.iec.edp.caf.tenancy.core.TenantCache;
import io.iec.edp.caf.tenancy.core.repository.AppInstanceRepository;
import io.iec.edp.caf.tenancy.core.utils.DataValidator;
import lombok.extern.slf4j.Slf4j;
import lombok.var;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * TenantAppInstanceMgr$
 *
 * @author Hey Law
 * @create 2019年8月22日10:50:12$
 */
@Slf4j
public class TenantAppInstanceMgr {

    private final DbConnectionManager dbMgr;

    private final DbMappingManager mappingMgr;

    private final ClusterManager clusterManager;

    private final ClusterAppMgr relationManager;

    private final AppInstanceRepository appRepository;

    private final TenantCache tenantCache;

    public TenantAppInstanceMgr(DbConnectionManager dbMgr, DbMappingManager mappingMgr, ClusterManager clusterManager, ClusterAppMgr relationManager,
                                AppInstanceRepository appRepository, TenantCache tenantCache)
    {
        this.dbMgr = dbMgr;
        this.mappingMgr = mappingMgr;
        this.clusterManager = clusterManager;
        this.relationManager = relationManager;
        this.appRepository = appRepository;
        this.tenantCache = tenantCache;
    }

    private final ConcurrentHashMap<Integer, List<AppInstanceInfo>> tenantAppInfos = new ConcurrentHashMap<>();

    /**
     * 根据租户标识获取租户信息（不含相关的附属信息）
     *
     * @param
     * @return
     * @Date: 2019/8/22
    */
    public AppInstanceInfo get(int tenantId, String appInstanceCode)
    {
        DataValidator.checkForNullReference(tenantId, "tenantId");
        DataValidator.checkForEmptyString(appInstanceCode, "appInstanceCode");

        AppInstanceInfo info = null;
        info = tenantCache.hashGet(getCacheKey(tenantId), appInstanceCode, AppInstanceInfo.class);
        if (info == null)
        {
            info = this.appRepository.findByCodeAndTenantId(appInstanceCode,tenantId);

            //现在应用实例还是写死的pg01，暂时加上兼容处理，后续删除
            if (info == null) {
                List<AppInstanceInfo> infos = this.appRepository.findAllByTenantId(tenantId);
                if (infos != null && infos.size() > 0)
                    info = infos.get(0);
            }

            if (info == null)
            {
//                log.error(String.format("根据租户:%d和实例编号:%s未找到对应的实例信息，请检查!",tenantId,appInstanceCode));
                throw new NoMatchingAppInstanceFound("", "AppInstanceInfo",
                        String.format("根据租户:%d和实例编号:%s未找到对应的实例信息，请检查!",tenantId,appInstanceCode),
                        null, ExceptionLevel.Error, false);
            }
            tenantCache.hashSet(getCacheKey(tenantId), appInstanceCode, info);
        }
        
        return info;
    }

    /**
     * 根据租户编号获取所有的租户实例基本信息(只获取实例基本信息)
     *
     * @param
     * @return
     * @Date: 2019/8/22
    */
    public List<AppInstanceInfo> getAllAppInstInfos(int tenantId)
    {
        DataValidator.checkForNullReference(tenantId, "tenantId");

        var infos = tenantAppInfos.getOrDefault(tenantId, null);
        if (infos == null)
        {
            infos = this.appRepository.findAllByTenantId(tenantId);

            if (infos != null && infos.size() > 0)
            {
                tenantAppInfos.putIfAbsent(tenantId, infos);
            }
        }
        return infos;
    }

    /**
     * 新增租户应用实例
     *
     * @param
     * @return
     * @Date: 2019/8/22
    */
    public void add(AppInstanceInfo appInstanceInfo)
    {
        DataValidator.checkForNullReference(appInstanceInfo, "appInstanceInfo");
        this.update(appInstanceInfo);
    }

    /**
     * 更新租户应用实例
     *
     * @param
     * @return
     * @Date: 2019/8/22
    */
    public boolean update(AppInstanceInfo appInstanceInfo)
    {
        DataValidator.checkForNullReference(appInstanceInfo, "appInstanceInfo");

        this.appRepository.save(appInstanceInfo);
//        if (appInstanceInfo.getSuDBMappings() != null)
//        {
//            this.mappingMgr.add(appInstanceInfo.getId(), appInstanceInfo.getSuDBMappings());
//        }
//
//        if (appInstanceInfo.getDbConnectionInfos() != null)
//        {
//            this.dbMgr.add(appInstanceInfo.getDbConnectionInfos());
//        }

        if (appInstanceInfo.getClusterId().isEmpty())
        {
            this.relationManager.add(appInstanceInfo.getId(), appInstanceInfo.getClusterId());
        }

        //删除缓存
        tenantCache.remove(getCacheKey(appInstanceInfo.getTenantId()));
        tenantAppInfos.remove(appInstanceInfo.getTenantId());
        return true;
    }


    /**
     * 根据租户标识删除租户信息
     *
     * @param
     * @return
     * @Date: 2019/8/22
    */
    public boolean remove(int tenantId, String appInstanceCode)
    {
        DataValidator.checkForNullReference(tenantId, "tenantId");
        DataValidator.checkForEmptyString(appInstanceCode, "appInstanceCode");

        AppInstanceInfo info;

        info = this.get(tenantId, appInstanceCode);

        this.dbMgr.removeByAppInstanceId(info.getId());
        this.mappingMgr.removeByAppInstanceId(info.getId());
        this.appRepository.delete(info);

        //删除缓存
        //删除缓存
        tenantCache.remove(getCacheKey(tenantId));
        tenantAppInfos.remove(tenantId);
        return true;
    }

    /**
     * 根据租户标识获取缓存key
     *
     * @param
     * @return
     * @Date: 2019/8/22
    */
    private String getCacheKey(int tenantId)
    {
        return String.format("App_%s", tenantId);
    }

}
